﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Dynamic;
using Newtonsoft.Json;

namespace Zsnd.Helpers {
    public class FilterHelper<T> {
        public Filter Filter { get; set; }
        public IQueryable<T> Query { get; set; }
        public IList<FilterRule> ExcludeRules { get; private set; }//过滤规则是用来输入
        #region Static Members
        static Dictionary<string, string> keywords = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase) { 
            {"eq", "="},
            {"ne", "!="},
            {"lt", "<"},
            {"le", "<="},
            {"gt", ">"},
            {"ge", ">="},
            {"bw", ">="},
            {"bn", "<"},
            {"in", "con"},
            {"ni", ""},
            {"ew", "<="},
            {"en", ">"},
            {"cn", "con"},
            {"nc", ""}
        };
        static string[] groupOp = { "and", "or" };
        static string[] op = { "eq", "ne", "lt", "le", "gt", "ge", "bw", "bn", "in", "ni", "ew", "en", "cn", "nc" };

        //static FilterHelper() {
        //    keywords = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
        //    keywords.Add("eq", "=");
        //    keywords.Add("ne", "!=");
        //    keywords.Add("lt", "<");
        //    keywords.Add("le", "<=");
        //    keywords.Add("gt", ">");
        //    keywords.Add("ge", ">=");
        //    keywords.Add("bw", ">=");
        //    keywords.Add("bn", "<");
        //    keywords.Add("in", "con");
        //    keywords.Add("ni", "");
        //    keywords.Add("ew", "<=");
        //    keywords.Add("en", ">");
        //    keywords.Add("cn", "con");
        //    keywords.Add("nc", "");
        //}
        #endregion
        #region Constructor
        public FilterHelper(IQueryable<T> query, string filters, params string[] excludes) {
            this.Query = query;
            this.Filter = DeserializeFilters(filters);
            this.ExcludeRules = InitializeExcludeRules(excludes);
        }

        public FilterHelper(IQueryable<T> query, string filters) : this(query, filters, null) { }
        public FilterHelper() { }

        private Filter DeserializeFilters(string filters) {
            if (string.IsNullOrWhiteSpace(filters)) return null;
            Filter filter = JsonConvert.DeserializeObject<Filter>(filters);
            return filter;
        }

        private IList<FilterRule> InitializeExcludeRules(string[] excludes) {
            if (Filter == null) return null;
            if (excludes == null || excludes.Count() == 0) return null;//需要过滤的字段不存在那么就不必要初始化过滤规则了

            IList<FilterRule> rules = Filter.Rules;
            if (rules == null && rules.Count == 0) return null; //过滤规则不存在，返回
            //do ExcludeRulesEnmu

            var excludeList = new List<FilterRule>();
            //foreach (FilterRule rule in rules) {
            //    if (ExcludeFields.Contains(rule.Field)) {
            //        rules.Remove(rule);
            //        list.Add(rule);
            //    }
            //}
            for (int i = rules.Count; i > 0; i--) {
                if (excludes.Contains(rules[i - 1].Field)) {
                    excludeList.Add(rules[i - 1]);
                    rules.Remove(rules[i - 1]);
                    i = excludeList.Count - 1;
                }
            }
            if (excludeList.Count > 0) return excludeList;
            return null;
        }
        #endregion


        //public IQueryable<T> GetQuery() {
        //    object[] value = null;
        //    string filter = GetFilterString(out value);
        //    if (!string.IsNullOrWhiteSpace(filter) && value != null) {
        //        IQueryable<T> query = Query.Where(filter, value);
        //        return query;
        //    }
        //    return null;
        //}
        public IQueryable<T> GetQuery() {
            if (Filter == null || Filter.Rules.Count == 0) return Query;
            object[] value = null;
            string filter = GetWhereParameters(out value);
            if (!string.IsNullOrWhiteSpace(filter) && value != null) {
                Query = Query.Where(filter, value);
            }
            return Query;
        }

        private string GetWhereParameters(out object[] value) {
            //if (Filter == null) throw new Exception("过滤条件不存在");
            ValidateGroupOp(Filter.GroupOp);
            if (Filter.Rules == null || Filter.Rules.Count < 1) {
                value = null;
                return null;
            }
            string filter = "";
            value = new object[Filter.Rules.Count];
            int i = 0;
            foreach (FilterRule frule in Filter.Rules) {
                ValidateOp(frule.Op);
                //ValidateData(frule.Data);
                if (string.IsNullOrWhiteSpace(frule.Data)) continue;
                filter += frule.Field + " " + keywords[frule.Op] + " " + "@" + i.ToString() + " " + Filter.GroupOp + " ";
                value[i++] = GetData(frule);
            }
            if (filter.Length < 5) return null;
            return filter.Substring(0, filter.Length - 4).Trim();
        }

        private object GetData(FilterRule frule) {
            string op = frule.Op;
            string data = frule.Data;
            DateTime result;
            if (DateTime.TryParse(data, out result)) {
                return result;
            }
            if (op == "eq" || op == "ge" || op == "le") {
                int i;
                if (int.TryParse(data, out i)) {
                    return i;
                }
                double d;
                if (double.TryParse(data, out d)) {
                    return d;
                }
            }
            return data;
        }
        void ValidateGroupOp(string gOp) {
            if (!groupOp.Contains(gOp.ToLower())) throw new ArgumentException("组操作符无效");
        }

        void ValidateOp(string op1) {
            if (!op.Contains(op1.ToLower())) throw new ArgumentException("操作符无效");
        }

        void ValidateData(string data) {
            if (string.IsNullOrWhiteSpace(data)) throw new ArgumentException("过滤数据为空");
        }

    }

    public class Filter {
        public string GroupOp { get; set; }
        public IList<FilterRule> Rules { get; set; }
    }
    public class FilterRule {
        public string Field { get; set; }
        public string Op { get; set; }
        public string Data { get; set; }
    }
}